package com.senyint.hip.fhir.web;

import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.client.impl.GenericClient;
import ca.uhn.fhir.rest.gclient.DateClientParam;
import ca.uhn.fhir.rest.gclient.IQuery;
import ca.uhn.fhir.rest.gclient.StringClientParam;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import com.senyint.hip.fhir.interceptor.CaptureInterceptor;
import com.senyint.hip.fhir.util.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r4.model.*;
import org.springframework.web.bind.annotation.*;

import java.util.Date;

/**
 * *******description*******
 * 手术
 * *************************
 *
 * @author ChenPan
 * @date 2019/7/2 10:15
 */
@RestController
@RequestMapping("/procedure")
@Slf4j
public class ProcedureController extends FhirBaseController {

    public static final String RESOURCE_TYPE = "Procedure";

    @PostMapping()
    public String createProcedure(@RequestBody String data) {
        Procedure procedure = convertProcedure(data);

        CaptureInterceptor interceptor = new CaptureInterceptor();
        GenericClient client = newClient(tempData.getBaseServer(), interceptor);

        MethodOutcome out = client.create().resource(procedure).execute();

        return new Gson().toJson(out);

    }

    @PutMapping("/{id}")
    public String updateProcedure(@PathVariable("id") String id, @RequestBody String data) throws FHIRException {
        Procedure procedure = convertProcedure(data);

        CaptureInterceptor interceptor = new CaptureInterceptor();
        GenericClient client = newClient(tempData.getBaseServer(), interceptor);

        MethodOutcome out = client.update(id, procedure);

        return new Gson().toJson(out);

    }

    @GetMapping("/search")
    public String searchResource(@RequestParam(value = "patientId", required = false) String patientId,
                                 @RequestParam(value = "procedureCode", required = false) String procedureCode,
                                 @RequestParam(value = "procedureName", required = false) String procedureName,
                                 @RequestParam(value = "start", required = false) String start,
                                 @RequestParam(value = "end", required = false) String end,
                                 @RequestParam(value = "id", required = false) String id) {
        log.debug("server:{}", tempData.getBaseServer());

        GenericClient client = (GenericClient) ctx.newRestfulGenericClient(tempData.getBaseServer());
        IQuery query = client.search().forResource(RESOURCE_TYPE);
        if (StringUtils.isNotBlank(id)) {
            return new Gson().toJson(client.read().resource(RESOURCE_TYPE).withId(id).execute());
        }
        if (StringUtils.isBlank(id) && StringUtils.isAllBlank(patientId, procedureCode, procedureName,start,end)) {
            return new Gson().toJson(client.search().forResource(RESOURCE_TYPE).returnBundle(Bundle.class).execute());
        } else {
            if (StringUtils.isNotBlank(patientId)) {
                query.and(new StringClientParam("patient").matches().value("Patient/" + patientId));
            }
            if (StringUtils.isNotBlank(procedureCode)) {
                query.and(new StringClientParam("code").matches().value(procedureCode));
            }
            if (StringUtils.isNotBlank(procedureName)) {
                query.and(new StringClientParam("name").matches().value(procedureName));
            }
            if (StringUtils.isNotBlank(start)) {
                query.and(new DateClientParam("date").afterOrEquals().second(DateUtils.string2Date(start)));
            }
            if (StringUtils.isNotBlank(end)) {
                query.and(new DateClientParam("date").beforeOrEquals().second(DateUtils.string2Date(end)));
            } 
            return new Gson().toJson(query.returnBundle(Bundle.class).execute());
        }

    }

    protected Procedure convertProcedure(String data) {
        JSONObject jsonObject = JSON.parseObject(data);

        Procedure procedure = new Procedure();
        procedure.addIdentifier()
                .setSystem("http://org.cn/org/12345/surgery")
                .setValue(jsonObject.getString("procedureId"));

        procedure.setStatus(Procedure.ProcedureStatus.COMPLETED);

        procedure.setCategory(new CodeableConcept()
                .addCoding(new Coding("http://snomed.info/sct",
                        jsonObject.getString("categoryCode"),
                        jsonObject.getString("categoryName")))
                .setText(jsonObject.getString("categoryName"))
        );

        procedure.setCode(new CodeableConcept()
                .addCoding(new Coding("http://snomed.info/sct",
                        jsonObject.getString("procedureCode"),
                        jsonObject.getString("procedureName")))
                .setText(jsonObject.getString("procedureName")));

        procedure.setSubject(new Reference("Patient/" + jsonObject.getString("patientId"))
                .setDisplay(jsonObject.getString("name")));
        procedure.setEncounter(new Reference(/*"Encounter/" + jsonObject.getString("encId")*/));

        procedure.setPerformed(new Period()
                .setStart(DateUtils.string2Date(jsonObject.getString("start")))
                .setEnd(DateUtils.string2Date(jsonObject.getString("end")))
        );
        procedure.addPerformer().setFunction(new CodeableConcept().setText("主刀医师"))
                .setActor(new Reference().setDisplay(jsonObject.getString("doctorName")));
        procedure.addPerformer().setFunction(new CodeableConcept().setText("I助"))
                .setActor(new Reference().setDisplay(jsonObject.getString("firstAssistantName")));
        procedure.addPerformer().setFunction(new CodeableConcept().setText("II助"))
                .setActor(new Reference().setDisplay(jsonObject.getString("secondAssistantName")));

        procedure.setLocation(new Reference().setDisplay(jsonObject.getString("room")));
        procedure.addReasonReference(new Reference().setDisplay(jsonObject.getString("icdName")));
        procedure.addBodySite(new CodeableConcept()
                .addCoding(new Coding("http://snomed.info/sct",
                        jsonObject.getString("bodySiteCode"),
                        jsonObject.getString("bodySiteName")))
                .setText(jsonObject.getString("bodySiteName"))
        );
        procedure.setOutcome(new CodeableConcept()
                .addCoding(new Coding("http://snomed.info/sct",
                        jsonObject.getString("resultCode"),
                        jsonObject.getString("result")))
                .setText(jsonObject.getString("result"))
        );

        return procedure;
    }
}
